/**
 * @class   wosh::UserManager
 * @brief   CoreModule holding WOSH Users and Groups. Distributed component.
 * 
 * \image html diagrams/UserManager.png "wosh::UserManager UML diagram"
 *
 *
 *
 * @ingroup CoreModules
 ****************************************************************************
 * @version 0.7.000 $Id: UserManager.h 2836 2010-08-03 01:35:26Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/*! \page page_core
 * \htmlonly <hr/> \endhtmlonly
 * \section page_core_users Users
 *
 * wosh::UserManager collects users (object) instances (wosh::User) and offers
 * methods for accessing and updating information (properties) of Users.
 *
 * Users are loaded from a WOSH compatible database (see \ref page_core_database).
 * 
 *
 * \see wosh::UserManager
 * \see wosh::User
 *
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR UserS;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_UserManager_H__
 #define __WOSH_Core_UserManager_H__

 #include <woshDefs.h>
 #include <core/WoshModule.h>
 #include <core/Fact.h>
 #include <core/User.h>
 #include <core/UserGroup.h>


namespace wosh {

 #define _UserManager_NAME						"UserManager"
 #define _UserManager_URI						":Users"

 #define _UserManager_KEY_Users					"Users"
 #define _UserManager_KEY_UsersDB				"UsersDB"
 #define _UserManager_KEY_Groups				"Groups"
 #define _UserManager_KEY_GroupsDB				"GroupsDB"

 #define _UserManager_METHOD_listgroups			"listgroups"

 #define _UserManager_METHOD_listloc			"listloc"
 #define _UserManager_METHOD_forcelocation		"forcelocation"
 #define _UserManager_METHOD_listcomm			"listcomm"
 #define _UserManager_METHOD_rankcomm			"rankcomm"

 #define _UserManager_METHOD_search				"search"

 #define _UserManager_EVENT_UserListChanged		"UserListChanged"
 #define _UserManager_EVENT_GroupListChanged	"GroupListChanged"
 #define _UserManager_EVENT_located				"UserLocated"
 #define _UserManager_EVENT_UsersAtHome			"UsersAtHome"


class WoshKernel;

class UserManager : public WoshModule
 {
	WOSH_MODULE(wosh::UserManager)

	typedef MapT<std::string, User*> tStrUserMap;
	typedef MapT<std::string, UserGroup*> tStrUserGroupMap;


	protected:
		/**
		 * @brief  Default constructor. Call base constructor and initialize some properties and hosted methods.
		 *         Create default users and groups (such as \c root, \c nobody, etc()
		 * @param parent [in] WoshKernel singleton, passed to WoshModule constructor
		 * @note   Called by WoshKernel only. Static getter (gamma singleton) will return NULL until kernel is created.
		 * @see    createDefaultUsersGroups()
		 */
		UserManager( const WoshKernel* parent = NULL );

		/**
		 * @brief  Call base class implementation, load Users and Groups databases.
		 *         DSM is initialized.
		 * @return result of WoshModule::onKernelInitializing() + bus-creation result
		 */
		WRESULT onKernelInitializing();

		WRESULT onKernelStopping();

		friend class wosh::WoshKernel;

	public:
		/**
		 * @brief  Destructor. Users and Groups dataset are destroyed.
		 */
		virtual ~UserManager();


//@}
/** @name Public methods (not for bundles, usually hidden to most classes)
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Register a User. If a User with same name exists, it is updated. Reentrant.
		 * @param user [in] the user object to be registered, ownership is acquired
		 * @return WRET_ERR_PARAM if argument is NULL or its name is empty; WRET_OK else
		 * @see    registerUser_()
		 */
		WRESULT registerUser( User* user );

		WRESULT registerGroup( UserGroup* usergroup );

		virtual WRESULT loadUsers();

		virtual WRESULT loadGroups();

//@}
/** @name Public static methods (for bundles)
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Evaluate is User exists.
		 * @param username [in] the WOSH username, such as 'root'
		 * @return true when user is registered; false else
		 */
		static bool isUser( const std::string& username );
		/**
		 * @brief  Evaluate is User is member of a UserGroup.
		 * @param username [in] the WOSH username, such as 'root'
		 * @param groupname [in] the WOSH group name, such as 'root'
		 * @return true when user is member of the group; false else
		 */
		static bool isGroupOfUser( const std::string& username, const std::string& groupname );

		///@deprecated user-access model is going to be redesigned 
static WRESULT isAuthorized( const std::string& wosh_username, const SecurityTokenProvider* credentials );

		///@deprecated user-access model is going to be redesigned 
		static int getUserCountAtHome();

		///@deprecated user-access model is going to be redesigned 
		static std::vector<std::string> findUserByProperty( const std::string& key, const Variant& value, const SecurityToken* queryOwner = NULL );

		///@deprecated user-access model is going to be redesigned 
		static Variant getUserProperty( const std::string& username, const std::string& key, const SecurityToken* queryOwner = NULL );
		///@deprecated user-access model is going to be redesigned 
		static WRESULT setUserProperty( const std::string& username, const std::string& key, const Variant& data, const SecurityToken* queryOwner );

		///@deprecated user-access model is going to be redesigned 
		static std::string getUserLocation( const std::string& username, const SecurityToken* queryOwner = NULL );
		///@deprecated user-access model is going to be redesigned 
		static UserInfoCommmunicators* getUserCommunicators( const std::string& username, const SecurityToken* queryOwner = NULL );

		///@deprecated user-access model is going to be redesigned 
		static WRESULT setUserLocation( const std::string& username, const std::string& new_location, double probability = 0.0, short at_home = 2 );
		///@deprecated user-access model is going to be redesigned 
		static WRESULT setUserCommunicator( const std::string& user, const std::string& communicator, long timestamp, double ranking_offset = 0.0 );

//@}
/** @name Message Events (incoming message)
 * @{
 ******************************************************************************/
	public:
		void busMessage( const Message& message, const Bus* source );
//@}
/** @name Internal Mehods and Events management
 * @{
 ******************************************************************************/
	protected:
		friend class wosh::User;

	private:
		/**
		 * @brief  Access the UserManager singleton. Gamma Pattern.
		 *         Static reference is allocated and detroyed by WoshKernel on constructor/destructor respectively
		 * @return pointer to UserManager singleton. May be NULL (if kernel has not been allocated yet)
		 */
		static UserManager* getInstance();

	private:
		/**
		 * @brief  Register an User. If an User with same name exists, it is updated. Not Reentrant.
		 * @param user [in] the user to be registered, ownership is acquired
		 * @param raise_event [in] when true, it will broadcast a Fact on wosh.Bus.Security
		 * @return WRET_ERR_PARAM if argument is NULL or its name is empty; WRET_OK else
		 * @see    registerUser()
		 */
		WRESULT registerUser_( User* user, bool raise_event );
		/**
		 * @brief  Register a Group. Not Reentrant.
		 * @param usergroup [in] the group to be registered, ownership is acquired
		 * @param raise_event [in] when true, it will broadcast a Fact on wosh.Bus.Security
		 * @return WRET_ERR_PARAM if argument is NULL or its name is empty; WRET_ERR_ILLEGAL_USE if groups exists; WRET_OK else
		 * @see    registerUser()
		 */
		WRESULT registerGroup_( UserGroup* usergroup, bool raise_event );
		/**
		 * @brief  Create some default Users and Groups.
		 *         Groups:
		 *          - root [1]
		 *          - virtual [10]
		 *          - nobody [20]
		 *          - inhabitants [110]
		 *          - friends [3200]
		 *         Users:
		 *          - root [1], password is 'wosh', member of: root, virtual
		 *          - wosh [10], no-password, member of: root, virtual
		 *          - nobody [50], no-password, member of: nobody, virtual
		 *          - anonymous [52], no-password, member of: nobody, virtual
		 */
		void createDefaultUsersGroups();
//@}
	private:
		Response* mmDoGetUsersCommunicators( const Request* request );
		Response* mmDoGetUsersLocations ( const Request* request );
		Response* mmDoForceUserIn( const Message* requestMessage );
		Response* mmDoSearchUser( const Message* requestMessage );

	private:
		tStrUserMap users;			///< map of users [name, pointer]
		tStrUserGroupMap groups;	///< map of groups [name, pointer]
		URI GroupsVirtualURI;		///< base URI for groups (:/Users/Groups)

		BusConnector BusSecurity;	///< connector to wosh.Bus.Security


}; // class def



/**
 * @class   wosh::UserManager_UserListChanged
 * @brief   Raised when an user is added or updated.
 *
 * Internally, data is stored as wosh::List. Supports also wosh::Variant type.
 *
 * Fields are:
 *  - \c username [Variant::STRING] (always present, first item of the list)
 *  - \c action type (optional, default: new user)
 *
 * Some getters are provided for convenience:
 * \code

 * \endcode
 *
 * @see     wosh::Fact
 * @see     wosh::UserManager
 ****************************************************************************
 * @version 0.8.399 $Id: UserManager.h 2836 2010-08-03 01:35:26Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
class UserManager_UserListChanged : public Fact_ListChanged
 {
	WOSH_SERIALIZABLE(wosh::UserManager_UserListChanged)

	public:
		/**
		 * @brief  Empty constructor.
		 */
		UserManager_UserListChanged()
			: Fact_ListChanged( _UserManager_EVENT_UserListChanged ) { }
		/**
		 * @brief  Constructor with initializers.
		 * @param username [in] added, updated or removed item 
		 * @param list_event [in] raised event within list/item
		 */
		explicit UserManager_UserListChanged( const std::string& username, FACT_LIST_EVENT list_event )
			: Fact_ListChanged(username, list_event, _UserManager_EVENT_UserListChanged) { }
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the source object to be copied
		 */
		UserManager_UserListChanged( const UserManager_UserListChanged& m )
			: Fact_ListChanged(m) { }
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~UserManager_UserListChanged() { }

	public:
		/**
		 * @brief   Get name of the (updated) user
		 * @return  username as string
		 */
		std::string getUserName() const;

}; // class def



/**
 * @class   wosh::UserManager_GroupListChanged
 * @brief   Raised when an user is added or updated.
 *
 * Internally, data is stored as wosh::List. Supports also wosh::Variant type.
 *
 * Fields are:
 *  - \c username [Variant::STRING] (always present, first item of the list)
 *  - \c action type (optional, default: new user)
 *
 * Some getters are provided for convenience:
 * \code

 * \endcode
 *
 * @see     wosh::Fact
 * @see     wosh::UserManager
 ****************************************************************************
 * @version 0.8.399 $Id: UserManager.h 2836 2010-08-03 01:35:26Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
class UserManager_GroupListChanged : public Fact_ListChanged
 {
	WOSH_SERIALIZABLE(wosh::UserManager_GroupListChanged)

	public:
		/**
		 * @brief  Empty constructor.
		 */
		UserManager_GroupListChanged()
			: Fact_ListChanged( _UserManager_EVENT_GroupListChanged ) { }
		/**
		 * @brief  Constructor with initializers.
		 * @param groupname [in] added, updated or removed item 
		 * @param list_event [in] raised event within list/item
		 */
		explicit UserManager_GroupListChanged( const std::string& groupname, FACT_LIST_EVENT list_event )
			: Fact_ListChanged(groupname, list_event, _UserManager_EVENT_GroupListChanged) { }
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the source object to be copied
		 */
		UserManager_GroupListChanged( const UserManager_GroupListChanged& m )
			: Fact_ListChanged(m) { }
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~UserManager_GroupListChanged() { }

	public:
		/**
		 * @brief   Get name of the (updated) group
		 * @return  groupname as string
		 */
		std::string getGroupName() const;

}; // class def





}; // namespace wosh

#endif //__WOSH_Core_UserManager_H__
